package com.stars.easyms.datasource.transaction;

import com.stars.easyms.datasource.EasyMsDataSource;
import com.stars.easyms.datasource.util.EasyMsDataSourceUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Constants;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.transaction.*;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.support.*;
import org.springframework.util.Assert;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;

/**
 * <p>className: EasyMsDataSourceTransactionManager</p>
 * <p>description: EasyMs自定义DataSourceTransactionManager类：实现EASY-MS多数据源、多主多从、可负载均衡的数据源事务管理类</p>
 *
 * @author guoguifang
 * @date 2019-11-29 18:04
 * @since 1.4.2
 */
@Slf4j
@Setter
@Getter
public final class EasyMsDataSourceTransactionManager implements PlatformTransactionManager {

    private static final Constants CONSTANTS_FOR_DEFINITION = new Constants(TransactionDefinition.class);

    private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;

    private boolean nestedTransactionAllowed = true;

    private boolean useSavepointForNestedTransaction = true;

    private boolean validateExistingTransaction;

    private boolean globalRollbackOnParticipationFailure = true;

    private boolean failEarlyOnGlobalRollbackOnly;

    private boolean rollbackOnCommitFailure;

    private boolean shouldCommitOnGlobalRollbackOnly;

    private boolean enforceReadOnly;

    @NonNull
    @Override
    public TransactionStatus getTransaction(@Nullable TransactionDefinition definition) {
        // 如果没有给出事务定义，则使用默认值
        if (definition == null) {
            definition = new DefaultTransactionAttribute();
        }

        // 创建事务管理器
        EasyMsTransactionManager transactionManager = new EasyMsTransactionManager(this, definition);

        // 创建事务状态对象
        return new EasyMsTransactionStatus(transactionManager, isNewTransaction(transactionManager, definition));
    }

    @NonNull
    DefaultTransactionStatus getTransactionStatus(@NonNull TransactionDefinition definition, boolean existPreviousTransaction,
                                                  @NonNull EasyMsDataSource easyMsDataSource,
                                                  @NonNull EasyMsTransactionManager transactionManager) {
        EasyMsDataSourceTransactionObject transactionObject = new EasyMsDataSourceTransactionObject(easyMsDataSource);
        transactionObject.setSavepointAllowed(isNestedTransactionAllowed());

        // 缓存调试标志以避免重复检查。
        boolean debugEnabled = log.isDebugEnabled();

        // 若在上层已经存在事务
        if (existPreviousTransaction) {
            return handleExistingTransaction(definition, transactionObject, debugEnabled, easyMsDataSource, transactionManager);
        }

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            if (debugEnabled) {
                log.debug("Creating new transaction with name [{}]: {}", definition.getName(), definition);
            }
            // 若存在事务则开启事务，如果异常则恢复原来的状态然后抛出异常
            doBegin(transactionObject, definition, easyMsDataSource, transactionManager);
            return new DefaultTransactionStatus(transactionObject, true, true, definition.isReadOnly(), debugEnabled, null);
        } else {
            // 创建"空"事务:没有实际的事务
            if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && log.isWarnEnabled()) {
                log.warn("Custom isolation level specified but no actual transaction initiated;  " +
                        "isolation level will effectively be ignored: {}", definition);
            }
            return new DefaultTransactionStatus(null, true, true, definition.isReadOnly(), debugEnabled, null);
        }
    }

    @NonNull
    private DefaultTransactionStatus handleExistingTransaction(@NonNull TransactionDefinition definition,
                                                               @NonNull EasyMsDataSourceTransactionObject transactionObject,
                                                               boolean debugEnabled, @NonNull EasyMsDataSource easyMsDataSource,
                                                               @NonNull EasyMsTransactionManager transactionManager) {

        // 如果是PROPAGATION_NOT_SUPPORTED，不支持事务，则挂起当前事务，并返回"空"事务状态对象
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
            if (debugEnabled) {
                log.debug("Suspending current transaction");
            }
            return new DefaultTransactionStatus(null, false, true, definition.isReadOnly(), debugEnabled, null);
        }

        // 如果是PROPAGATION_REQUIRES_NEW，则创建一个新的事务
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
            if (debugEnabled) {
                log.debug("Suspending current transaction, creating new transaction with name [{}]", definition.getName());
            }
            doBegin(transactionObject, definition, easyMsDataSource, transactionManager);
            return new DefaultTransactionStatus(transactionObject, true, true, definition.isReadOnly(), debugEnabled, null);
        }

        // 剩余传播模式是PROPAGATION_SUPPORTS、PROPAGATION_REQUIRED、PROPAGATION_MANDATORY、PROPAGATION_NESTED
        EasyMsTransactionManager topTransactionManager = transactionManager.getTopTransactionManager();
        EasyMsTransactionStatusHolder topTransactionStatusHolder = topTransactionManager.getTransactionStatusHolder(easyMsDataSource);

        // 如果顶层事务里不存在当前easyMsDataSource的事务，则在顶层事务里创建当前easyMsDataSource的事务
        if (topTransactionStatusHolder == null || topTransactionStatusHolder.getConnectionHolder() == null) {
            topTransactionStatusHolder = topTransactionManager.newTransactionStatusHolder(easyMsDataSource);
        }
        ConnectionHolder connectionHolder = topTransactionStatusHolder.getConnectionHolder();
        Assert.notNull(connectionHolder, "Current transaction is not active");

        // 如果顶层事务可以获取到connectionHolder则把允许嵌套事务存在
        transactionObject.setConnectionHolder(connectionHolder);
        transactionManager.bindConnectionHolder(easyMsDataSource, connectionHolder);

        DefaultTransactionStatus status =
                new DefaultTransactionStatus(transactionObject, false, false, definition.isReadOnly(), debugEnabled, null);

        // 如果是PROPAGATION_NESTED，先判断是否允许嵌套事务，如果允许则判断是否允许在嵌套事务里使用SavePoint，如果不可使用则使用新的事务状态对象
        if (transactionManager.isNestedAndUseSavepoint()) {
            if (debugEnabled) {
                log.debug("Creating nested transaction with name [{}]", definition.getName());
            }

            status.createAndHoldSavepoint();
            return status;
        }

        // 如果是PROPAGATION_SUPPORTS、PROPAGATION_REQUIRED、PROPAGATION_MANDATORY、PROPAGATION_NESTED非useSavepoint的，则加入当前事务
        if (debugEnabled) {
            log.debug("Participating in existing transaction");
        }
        return status;
    }

    private void doBegin(@NonNull EasyMsDataSourceTransactionObject transactionObject, @NonNull TransactionDefinition definition,
                         @NonNull EasyMsDataSource easyMsDataSource, @NonNull EasyMsTransactionManager transactionManager) {
        Connection con = null;
        try {
            con = EasyMsDataSourceUtil.getConnection(easyMsDataSource);
            if (log.isDebugEnabled()) {
                log.debug("Acquired Connection [{}] for JDBC transaction", con);
            }
            ConnectionHolder connectionHolder = new ConnectionHolder(con);
            connectionHolder.requested();
            transactionObject.setConnectionHolder(connectionHolder);

            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            transactionObject.setPreviousIsolationLevel(previousIsolationLevel);

            // 如果需要，切换到手动提交，比较耗费性能
            if (con.getAutoCommit()) {
                transactionObject.setMustRestoreAutoCommit();
                if (log.isDebugEnabled()) {
                    log.debug("Switching JDBC Connection [{}] to manual commit", con);
                }
                con.setAutoCommit(false);
            }

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                transactionObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // 绑定connectionHolder到当前线程
            transactionManager.bindConnectionHolder(easyMsDataSource, connectionHolder);
        } catch (Throwable ex) {
            DataSourceUtils.releaseConnection(con, easyMsDataSource);
            transactionObject.setConnectionHolder(null);
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

    /**
     * 检查当前事务是否有效并返回是否有真实事务激活
     */
    boolean isActualTransactionActive(@NonNull TransactionDefinition definition, EasyMsTransactionManager previousTransactionManager,
                                      boolean joinPreviousTransaction) {
        if (previousTransactionManager != null && previousTransactionManager.isActualTransactionActive()) {
            // 如果已经存在事务，但是传播机制为PROPAGATION_NEVER时抛出异常
            if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
                throw new IllegalTransactionStateException(
                        "Existing transaction found for transaction marked with propagation 'never'");
            }

            if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED && !isNestedTransactionAllowed()) {
                throw new NestedTransactionNotSupportedException(
                        "Transaction manager does not allow nested transactions by default - " +
                                "specify 'nestedTransactionAllowed' property with value 'true'");
            }

            if (joinPreviousTransaction && isValidateExistingTransaction()) {
                Integer currentIsolationLevel = previousTransactionManager.getCurrentTransactionIsolationLevel();
                boolean isIsolationMismatch = definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT
                        && (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel());
                if (isIsolationMismatch) {
                    throw new IllegalTransactionStateException("Participating transaction with definition [" +
                            definition + "] specifies isolation level which is incompatible with existing transaction: " +
                            (currentIsolationLevel != null ?
                                    CONSTANTS_FOR_DEFINITION.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) : "(unknown)"));
                }
                if (!definition.isReadOnly() && previousTransactionManager.isCurrentTransactionReadOnly()) {
                    throw new IllegalTransactionStateException("Participating transaction with definition [" +
                            definition + "] is not marked as read-only but existing transaction is");
                }
            }

            return definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_SUPPORTS
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED;
        } else {
            // 检查新事务的定义设置
            if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
                throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
            }

            // 若传播机制为PROPAGATION_MANDATORY，且当前事务不存在，则抛出异常
            if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
                throw new IllegalTransactionStateException(
                        "No existing transaction found for transaction marked with propagation 'mandatory'");
            }

            return definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW
                    || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED;
        }
    }

    /**
     * 判断是否需要加入上个事务
     */
    boolean isJoinPreviousTransaction(@NonNull TransactionDefinition definition) {
        return definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
                || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY
                || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_SUPPORTS
                || (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED && !isUseSavepointForNestedTransaction());
    }

    /**
     * 判断是否是嵌套事务并且使用savepoint
     */
    boolean isNestedAndUseSavepoint(@NonNull TransactionDefinition definition) {
        return definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED && isUseSavepointForNestedTransaction();
    }

    @Override
    public void commit(@Nullable TransactionStatus status) {
        Assert.isTrue(status instanceof EasyMsTransactionStatus, "It is not a Easy-Ms TransactionStatus");
        EasyMsTransactionManager transactionManager = ((EasyMsTransactionStatus) status).getTransactionManager();
        try {
            Map<EasyMsDataSource, EasyMsTransactionStatusHolder> transactionStatusHolderMap = transactionManager.getTransactionStatusHolderMap();
            if (!transactionStatusHolderMap.isEmpty()) {
                boolean isRollback = status.isRollbackOnly();
                if (isRollback && log.isDebugEnabled()) {
                    log.debug("Transactional code has requested rollback");
                }

                Throwable throwable = commitOrRollback(transactionStatusHolderMap, !isRollback);
                if (throwable != null) {
                    log.error("Transaction {} exception: ", isRollback ? "rollback" : "commit", throwable);
                }
            }
        } finally {
            transactionManager.restoreThreadLocalStatus();
        }
    }

    @Override
    public void rollback(@Nullable TransactionStatus status) {
        Assert.isTrue(status instanceof EasyMsTransactionStatus, "It is not a Easy-Ms TransactionStatus");
        EasyMsTransactionManager transactionManager = ((EasyMsTransactionStatus) status).getTransactionManager();
        try {
            if (transactionManager.isJoinPreviousTransaction()) {
                transactionManager.setRollbackOnly();
            } else {
                Map<EasyMsDataSource, EasyMsTransactionStatusHolder> transactionStatusHolderMap = transactionManager.getTransactionStatusHolderMap();
                if (!transactionStatusHolderMap.isEmpty()) {
                    Throwable throwable = commitOrRollback(transactionStatusHolderMap, false);
                    if (throwable != null) {
                        log.error("Transaction rollback exception: ", throwable);
                    }
                }
            }
        } finally {
            transactionManager.restoreThreadLocalStatus();
        }
    }

    @Nullable
    Throwable commitOrRollback(@NonNull Map<EasyMsDataSource, EasyMsTransactionStatusHolder> transactionStatusHolderMap, boolean isCommit) {
        Throwable throwable = null;
        for (EasyMsTransactionStatusHolder easyMsTransactionStatusHolder : transactionStatusHolderMap.values()) {
            try {
                if (isCommit) {
                    commit(easyMsTransactionStatusHolder);
                } else {
                    rollback(easyMsTransactionStatusHolder);
                }
            } catch (Throwable t) {
                if (throwable == null) {
                    throwable = t;
                } else {
                    throwable.addSuppressed(t);
                }
            }
        }
        return throwable;
    }

    private void commit(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        DefaultTransactionStatus transactionStatus = transactionStatusHolder.getTransactionStatus();
        Assert.notNull(transactionStatus, "Transaction status does not exist");
        if (transactionStatus.isCompleted()) {
            throw new IllegalTransactionStateException(
                    "Transaction is already completed - do not call commit or rollback more than once per transaction");
        }

        if (transactionStatus.isLocalRollbackOnly()) {
            if (transactionStatus.isDebug()) {
                log.debug("Transactional code has requested rollback");
            }

            processRollback(transactionStatusHolder, false);
            return;
        }

        if (!isShouldCommitOnGlobalRollbackOnly() && transactionStatus.isGlobalRollbackOnly()) {
            if (transactionStatus.isDebug()) {
                log.debug("Global transaction is marked as rollback-only but transactional code requested commit");
            }

            processRollback(transactionStatusHolder, true);
            return;
        }

        processCommit(transactionStatusHolder);
    }

    private void rollback(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        DefaultTransactionStatus transactionStatus = transactionStatusHolder.getTransactionStatus();
        if (transactionStatus == null) {
            return;
        }

        if (transactionStatus.isCompleted()) {
            throw new IllegalTransactionStateException(
                    "Transaction is already completed - do not call commit or rollback more than once per transaction");
        }

        processRollback(transactionStatusHolder, false);
    }

    private void processCommit(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        DefaultTransactionStatus status = transactionStatusHolder.getTransactionStatus();
        try {
            boolean beforeCompletionInvoked = false;

            try {
                boolean unexpectedRollback = false;
                triggerBeforeCommit(transactionStatusHolder);
                triggerBeforeCompletion(transactionStatusHolder);
                beforeCompletionInvoked = true;

                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        log.debug("Releasing transaction savepoint");
                    }

                    unexpectedRollback = status.isGlobalRollbackOnly();
                    status.releaseHeldSavepoint();
                } else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        log.debug("Initiating transaction commit");
                    }

                    unexpectedRollback = status.isGlobalRollbackOnly();
                    doCommit(status);
                } else if (isFailEarlyOnGlobalRollbackOnly()) {
                    unexpectedRollback = status.isGlobalRollbackOnly();
                }

                // 如果我们有一个只回滚的全局标记，但仍然没有从commit中获得相应的异常，则抛出UnexpectedRollbackException
                if (unexpectedRollback) {
                    throw new UnexpectedRollbackException(
                            "Transaction silently rolled back because it has been marked as rollback-only");
                }
            } catch (UnexpectedRollbackException ex) {
                // 只能由doCommit引起
                triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_ROLLED_BACK);
                throw ex;
            } catch (TransactionException ex) {
                // 只能由doCommit引起
                if (isRollbackOnCommitFailure()) {
                    doRollbackOnCommitException(transactionStatusHolder, ex);
                } else {
                    triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_UNKNOWN);
                }
                throw ex;
            } catch (RuntimeException | Error ex) {
                if (!beforeCompletionInvoked) {
                    triggerBeforeCompletion(transactionStatusHolder);
                }

                doRollbackOnCommitException(transactionStatusHolder, ex);
                throw ex;
            }

            // 触发afterCommit回调，抛出的异常会传播到调用方，但事务仍然被视为已提交。
            try {
                triggerAfterCommit(transactionStatusHolder);
            } finally {
                triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_COMMITTED);
            }

        } finally {
            cleanupAfterCompletion(status);
        }
    }

    private void triggerBeforeCommit(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        DefaultTransactionStatus status = transactionStatusHolder.getTransactionStatus();
        if (status.isDebug()) {
            log.debug("Triggering beforeCommit synchronization");
        }

        for (TransactionSynchronization synchronization : transactionStatusHolder.getSynchronizations()) {
            synchronization.beforeCommit(status.isReadOnly());
        }
    }

    private void triggerBeforeCompletion(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        if (transactionStatusHolder.getTransactionStatus().isDebug()) {
            log.debug("Triggering beforeCompletion synchronization");
        }

        for (TransactionSynchronization synchronization : transactionStatusHolder.getSynchronizations()) {
            try {
                synchronization.beforeCompletion();
            } catch (Throwable tsex) {
                log.error("TransactionSynchronization.beforeCompletion threw exception", tsex);
            }
        }
    }

    private void doCommit(@NonNull DefaultTransactionStatus status) {
        EasyMsDataSourceTransactionObject transactionObject = (EasyMsDataSourceTransactionObject) status.getTransaction();
        Connection con = transactionObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            log.debug("Committing JDBC transaction on Connection [{}]", con);
        }

        try {
            con.commit();
        } catch (SQLException ex) {
            throw new TransactionSystemException("Could not commit JDBC transaction", ex);
        }
    }

    private void doRollbackOnCommitException(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder, Throwable ex) {
        DefaultTransactionStatus status = transactionStatusHolder.getTransactionStatus();
        try {
            if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    log.debug("Initiating transaction rollback after commit exception", ex);
                }

                doRollback(status);
            } else if (status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) {
                if (status.isDebug()) {
                    log.debug("Marking existing transaction as rollback-only after commit exception", ex);
                }

                doSetRollbackOnly(status);
            }
        } catch (RuntimeException | Error rbex) {
            log.error("Commit exception overridden by rollback exception", ex);
            triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_UNKNOWN);
            throw rbex;
        }

        triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_ROLLED_BACK);
    }

    private void triggerAfterCompletion(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder, int completionStatus) {
        DefaultTransactionStatus status = transactionStatusHolder.getTransactionStatus();
        Set<TransactionSynchronization> synchronizations = transactionStatusHolder.getSynchronizations();
        if (!status.hasTransaction() || status.isNewTransaction()) {
            if (status.isDebug()) {
                log.debug("Triggering afterCompletion synchronization");
            }

            // 当前范围没有事务或新事务—>立即调用afterCompletion回调
            for (TransactionSynchronization synchronization : synchronizations) {
                try {
                    synchronization.afterCompletion(completionStatus);
                } catch (Throwable tsex) {
                    log.error("TransactionSynchronization.afterCompletion threw exception", tsex);
                }
            }
        } else if (!synchronizations.isEmpty()) {
            // 我们参与的现有事务，控制在这个Spring事务管理器的范围之外—>尝试向现有(JTA)事务注册一个完成后回调。
            log.debug("Cannot register Spring after-completion synchronization with existing transaction - " +
                    "processing Spring after-completion callbacks immediately, with outcome status 'unknown'");

            for (TransactionSynchronization synchronization : synchronizations) {
                try {
                    synchronization.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
                } catch (Throwable tsex) {
                    log.error("TransactionSynchronization.afterCompletion threw exception", tsex);
                }
            }
        }
    }

    private void triggerAfterCommit(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder) {
        if (transactionStatusHolder.getTransactionStatus().isDebug()) {
            log.debug("Triggering afterCommit synchronization");
        }

        for (TransactionSynchronization synchronization : transactionStatusHolder.getSynchronizations()) {
            synchronization.afterCommit();
        }
    }

    private void processRollback(@NonNull EasyMsTransactionStatusHolder transactionStatusHolder, boolean unexpected) {
        DefaultTransactionStatus status = transactionStatusHolder.getTransactionStatus();
        try {
            boolean unexpectedRollback = unexpected;

            try {
                triggerBeforeCompletion(transactionStatusHolder);

                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        log.debug("Rolling back transaction to savepoint");
                    }

                    status.rollbackToHeldSavepoint();
                } else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        log.debug("Initiating transaction rollback");
                    }

                    doRollback(status);
                } else {
                    if (status.hasTransaction()) {
                        if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                            if (status.isDebug()) {
                                log.debug("Participating transaction failed - marking existing transaction as rollback-only");
                            }

                            doSetRollbackOnly(status);
                        } else if (status.isDebug()) {
                            log.debug("Participating transaction failed - letting transaction originator decide on rollback");
                        }
                    } else {
                        log.debug("Should roll back transaction but cannot - no transaction available");
                    }
                    // 只有当我们被要求提前失败时，意外回滚才重要
                    if (!isFailEarlyOnGlobalRollbackOnly()) {
                        unexpectedRollback = false;
                    }
                }
            } catch (RuntimeException | Error ex) {
                triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_UNKNOWN);
                throw ex;
            }

            triggerAfterCompletion(transactionStatusHolder, TransactionSynchronization.STATUS_ROLLED_BACK);

            // 如果我们有一个只回滚的全局标记，那么就抛出一个UnexpectedRollbackException
            if (unexpectedRollback) {
                throw new UnexpectedRollbackException(
                        "Transaction rolled back because it has been marked as rollback-only");
            }
        } finally {
            cleanupAfterCompletion(status);
        }
    }

    private void doRollback(@NonNull DefaultTransactionStatus status) {
        EasyMsDataSourceTransactionObject transactionObject = (EasyMsDataSourceTransactionObject) status.getTransaction();
        Connection con = transactionObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            log.debug("Rolling back JDBC transaction on Connection [{}]", con);
        }

        try {
            con.rollback();
        } catch (SQLException ex) {
            throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
        }
    }

    private void doSetRollbackOnly(@NonNull DefaultTransactionStatus status) {
        EasyMsDataSourceTransactionObject transactionObject = (EasyMsDataSourceTransactionObject) status.getTransaction();
        if (status.isDebug()) {
            log.debug("Setting JDBC transaction [{}] rollback-only", transactionObject.getConnectionHolder().getConnection());
        }

        transactionObject.setRollbackOnly();
    }

    private void cleanupAfterCompletion(@NonNull DefaultTransactionStatus status) {
        status.setCompleted();
        if (status.isNewTransaction()) {
            doCleanupAfterCompletion(status.getTransaction());
        }
    }

    private void doCleanupAfterCompletion(@NonNull Object transaction) {
        EasyMsDataSourceTransactionObject transactionObject = (EasyMsDataSourceTransactionObject) transaction;

        // 重置连接
        Connection con = transactionObject.getConnectionHolder().getConnection();
        try {
            if (transactionObject.isMustRestoreAutoCommit()) {
                con.setAutoCommit(true);
            }

            DataSourceUtils.resetConnectionAfterTransaction(con, transactionObject.getPreviousIsolationLevel(),
                    transactionObject.isReadOnly());
        } catch (Throwable ex) {
            log.debug("Could not reset JDBC Connection after transaction", ex);
        }

        if (log.isDebugEnabled()) {
            log.debug("Releasing JDBC Connection [{}] after transaction", con);
            log.debug("Returning JDBC Connection [{}] to DataSource", con);
        }

        try {
            con.close();
        } catch (SQLException ex) {
            log.error("Could not close JDBC Connection", ex);
        } catch (Throwable ex) {
            log.error("Unexpected exception on closing JDBC Connection", ex);
        }

        transactionObject.getConnectionHolder().clear();
    }

    private int determineTimeout(@NonNull TransactionDefinition definition) {
        if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
            return definition.getTimeout();
        }
        return this.defaultTimeout < TransactionDefinition.TIMEOUT_DEFAULT ? TransactionDefinition.TIMEOUT_DEFAULT : this.defaultTimeout;
    }

    private boolean isNewTransaction(@NonNull EasyMsTransactionManager transactionManager, @NonNull TransactionDefinition definition) {
        if (transactionManager.isExistPreviousTransaction()) {
            return definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW;
        }
        return true;
    }

    /**
     * 数据源事务对象，表示一个ConnectionHolder。被DataSourceTransactionManager用作事务对象。
     */
    private static class EasyMsDataSourceTransactionObject extends JdbcTransactionObjectSupport {

        private final EasyMsDataSource easyMsDataSource;

        private boolean mustRestoreAutoCommit;

        private EasyMsDataSourceTransactionObject(@NonNull EasyMsDataSource easyMsDataSource) {
            this.easyMsDataSource = easyMsDataSource;
        }

        private void setMustRestoreAutoCommit() {
            this.mustRestoreAutoCommit = true;
        }

        private boolean isMustRestoreAutoCommit() {
            return this.mustRestoreAutoCommit;
        }

        private void setRollbackOnly() {
            getConnectionHolder().setRollbackOnly();
        }

        @Override
        public boolean isRollbackOnly() {
            return getConnectionHolder().isRollbackOnly();
        }

        @Override
        public void flush() {
            if (EasyMsTransactionSynchronizationManager.isSynchronizationActive()) {
                EasyMsTransactionStatusHolder transactionStatusHolder =
                        EasyMsTransactionSynchronizationManager.newTransactionStatusHolder(this.easyMsDataSource);
                for (TransactionSynchronization synchronization : transactionStatusHolder.getSynchronizations()) {
                    synchronization.flush();
                }
            }
        }
    }
}